﻿using Microsoft.AspNetCore.Builder;
using System.Reflection;

namespace Service.Framework.AppStartup
{
    public abstract class StartupModule<TStartupModule> : IStartupModule where TStartupModule : IStartupModule, new()
    {
        //
        // 摘要:
        //     启动器执行循序，从小到大的顺序执行
        public virtual int Order { get; set; } = 328;


        //
        // 摘要:
        //     程序启动器
        protected StartupModule()
        {
            Type type = GetType();
            if (type.FullName != typeof(TStartupModule).FullName)
            {
                throw new Exception($"当前实例类型 {type.FullName} 与 泛型传入类型 {typeof(TStartupModule).FullName} 不一致!");
            }
        }

        //
        // 摘要:
        //     配置服务
        //
        // 参数:
        //   webApplicationBuilder:
        public virtual void ConfigureServices(WebApplicationBuilder webApplicationBuilder)
        {
        }

        //
        // 摘要:
        //     配置
        //
        // 参数:
        //   webApplication:
        public virtual void Configure(WebApplication webApplication)
        {
        }

        //
        // 摘要:
        //     程序启动 可以获取程序启动 urls
        //
        // 参数:
        //   webApplication:
        public virtual void ApplicationStarted(WebApplication webApplication)
        {
        }

        //
        // 摘要:
        //     程序停止中
        //
        // 参数:
        //   webApplication:
        public virtual void ApplicationStopping(WebApplication webApplication)
        {
        }

        //
        // 摘要:
        //     程序已经停止
        //
        // 参数:
        //   webApplication:
        public virtual void ApplicationStopped(WebApplication webApplication)
        {
        }

        //
        // 摘要:
        //     获取所有导入的启动器实例
        public List<IStartupModule> GetAllImportStartup()
        {
            Type type = GetType();
            CheckLoopImportStartup(type);
            IEnumerable<ImportStartupModuleAttribute> customAttributes = type.GetCustomAttributes<ImportStartupModuleAttribute>();
            List<IStartupModule> list = new List<IStartupModule>();
            list.Add(this);
            foreach (ImportStartupModuleAttribute item2 in customAttributes)
            {
                FindImportStartup(list, item2);
            }

            foreach (IStartupModule item in list)
            {
                if (list.Count((w) => w.GetType().FullName == item.GetType().FullName) > 1)
                {
                    list.RemoveAt(list.IndexOf(item));
                }
            }

            return list.OrderBy((w) => w.Order).ToList();
        }

        //
        // 摘要:
        //     查找导入启动器特性
        //
        // 参数:
        //   startups:
        //
        //   importStartupAttribute:
        private void FindImportStartup(List<IStartupModule> startups, ImportStartupModuleAttribute importStartupAttribute)
        {
            foreach (IStartupModule startup in importStartupAttribute.GetStartups())
            {
                if (!startups.Any((w) => w.GetType().FullName == startup.GetType().FullName))
                {
                    startups.Add(startup);
                }
            }

            foreach (Type startupType in importStartupAttribute.GetStartupTypes())
            {
                CheckLoopImportStartup(startupType);
                IEnumerable<ImportStartupModuleAttribute> customAttributes = startupType.GetCustomAttributes<ImportStartupModuleAttribute>();
                foreach (ImportStartupModuleAttribute item in customAttributes)
                {
                    FindImportStartup(startups, item);
                }
            }
        }

        //
        // 摘要:
        //     验证循环导入启动器类型
        //
        // 参数:
        //   startupType:
        private void CheckLoopImportStartup(Type startupType)
        {
            Type startupType2 = startupType;
            IEnumerable<ImportStartupModuleAttribute> customAttributes = startupType2.GetCustomAttributes<ImportStartupModuleAttribute>();
            foreach (ImportStartupModuleAttribute item in customAttributes)
            {
                if (item.GetStartupTypes().Any((w) => w.FullName == startupType2.FullName))
                {
                    throw new Exception($"错误的导入。类型 {startupType2.FullName} 特性标记 [ImportStartup] 不允许导入自身 {startupType2.FullName} 启动器类型！");
                }
            }
        }
    }
}
